import { useMemo } from 'react';
import { useMatches, useRouteError } from 'react-router-dom';

import { parseQuery, stringifyQuery, type LocationQueryRaw } from '@/router/tools';

/**
 * 自定义路由钩子，提供增强的路由操作方法
 * @returns 包含路由操作方法的对象
 *
 * @example
 * const router = useRouter();
 * router.push('/users', { id: '123' }); // 带查询参数跳转
 * router.replace('/home'); // 替换当前路由
 */
export function useRouter() {
	const navigate = useNavigate();

	return useMemo(
		() => ({
			/**
			 * 返回上一页
			 * @example router.back();
			 */
			back: () => navigate(-1),

			/**
			 * 前进到下一页
			 * @example router.forward();
			 */
			forward: () => navigate(1),

			/**
			 * 刷新当前页面
			 * @example router.reload();
			 */
			reload: () => window.location.reload(),

			/**
			 * 导航到上级路由
			 * @example router.navigateUp();
			 */
			navigateUp: () => navigate('..'),

			/**
			 * 跳转到指定路径（支持查询参数和状态传递）
			 * @param path - 目标路径
			 * @param query - 查询参数对象
			 * @param state - 路由状态对象
			 * @param _replace - 是否替换当前路由（默认false）
			 *
			 * @example
			 * // 基本跳转
			 * router.push('/users');
			 * // 带查询参数
			 * router.push('/users', { page: '1', size: '10' });
			 * // 带状态和替换当前路由
			 * router.push('/profile', null, { from: 'home' }, true);
			 */
			push: (
				path: string,
				query?: LocationQueryRaw,
				state?: Record<string, unknown>,
				_replace?: boolean
			) => {
				let _path = path;

				// 处理查询参数
				if (query) {
					const search = stringifyQuery(query);
					_path = `${path}?${search}`;
				}

				navigate(_path, {
					replace: _replace,
					state
				});
			},

			/**
			 * 导航到指定路径（push的别名方法）
			 * @param path - 目标路径
			 * @example router.navigate('/dashboard');
			 */
			navigate: (path: string) => navigate(path),

			/**
			 * 替换当前路由
			 * @param path - 目标路径
			 * @example router.replace('/login');
			 */
			replace: (path: string) => navigate(path, { replace: true })
		}),
		[navigate]
	);
}
/**
 * 自定义路由钩子，用于获取当前路由信息
 *
 * @template T - 路由数据类型
 * @template Q - 查询参数类型，默认为Record<string, string>
 * @template P - 路径参数类型，默认为Record<string, string | string[]>
 *
 * @returns 返回包含路由信息的增强路由对象，包括：
 *   - 当前路由匹配信息
 *   - 错误对象(如果有)
 *   - 完整路径(fullPath)
 *   - hash值
 *   - 匹配的路由数组(matched)
 *   - 路径参数(params)
 *   - 路径名(pathname)
 *   - 查询参数(query)
 *   - 重定向标识(redirect)
 *   - 查询字符串(search)
 *
 * @remarks 使用useMemo优化性能，仅在fullPath变化时重新计算
 */
export function useRoute<
	T = unknown,
	Q extends Record<string, string> = Record<string, string>,
	P extends Record<string, string | string[]> = Record<string, string | string[]>
>() {
	const matches = useMatches();
	const routes = matches.at(-1);
	const { hash, pathname, search } = useLocation();
	const fullPath = pathname + search + hash;
	const query = parseQuery(search) as Q;
	const error = useRouteError() as Error | null;
	return useMemo(
		() =>
			({
				...routes,
				error,
				fullPath,
				hash,
				matched: matches.slice(1) as unknown as Router.EnhancedRoute<T>[],
				params: routes ? (getParams(routes.params as Record<string, string>, routes.id) as P) : {},
				pathname,
				query,
				redirect: null,
				search
			}) as unknown as Router.EnhancedRoute<T, Q, P>,
		[fullPath]
	);
}

/**
 * 获取上一个路由的上下文信息
 *
 * @returns 上一个路由的 Route 对象
 */
export function usePreviousRoute() {
	return useOutletContext<Router.EnhancedRoute>();
}
/**
 * 提取 catch-all 路由参数名（如 [...slug]）
 *
 * @param str 路由 id 字符串
 * @returns 捕获的参数名或 null
 */
function getCatchAllParam(str: string | undefined): string | null {
	if (!str) return null;
	const match = /\[\.\.\.(\w+)\]/.exec(str);
	return match ? match[1] : null;
}

/**
 * 处理路由参数，支持 catch-all 场景
 *
 * @param params 路由参数对象
 * @param id 路由 id
 * @returns 处理后的参数对象
 */
function getParams(
	params: Record<string, string> | undefined,
	id: string
): Record<string, string | string[]> | undefined {
	if (!params?.['*']) return params;
	const lastName = id.split('_').at(-1);
	const catchAllParam = getCatchAllParam(lastName);
	if (catchAllParam) {
		return { [catchAllParam]: params['*'].split('/') };
	}
	return params;
}
